package com.unitd.configclient.listener.impl;

import com.alibaba.fastjson.JSON;
import com.unitd.configclient.ConfigcenterContext;
import com.unitd.configclient.listener.IConfigChangeListener;
import com.unitd.frame.spring.prop.ResourceUtils;
import org.I0Itec.zkclient.IZkDataListener;
import org.I0Itec.zkclient.ZkClient;
import org.I0Itec.zkclient.ZkConnection;
import com.unitd.frame.comm.utils.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Map;
import java.util.Properties;

/**
 * @desc zookeeper配置中心改动监听类
 * 当配置中心服务端与zookeeper进行了继承后,客户端不需要直接与服务端进行交互,可以直接与zookeeper服务进行交互,从zookeeper中获取与当前应用相关的属性配置信息
 * @filename HttpConfigChangeListener.java
 * @copyright www.unitd.com
 * @author Hudan
 * @version 1.0
 * @date 2018/1/14
 */
public class ZkConfigChangeListener implements IConfigChangeListener {

	private final static Logger logger = LoggerFactory.getLogger(ZkConfigChangeListener.class);

	private final static String ROOT_PATH = "/confcenter";
	private static final String NOTIFY_UPLOAD_CMD = "upload";
	private ZkClient zkClient;
	private String zkServers;

	public ZkConfigChangeListener(String zkServers) {
		this.zkServers = zkServers;
	}

	/**
	 * @desc 获取当前服务与配置中心服务端进行心跳服务监听的方式(zookeeper/redis/http, 默认http)
	 * @return 同步方式名称
	 */
	@Override
	public String typeName() {
		return "zookeepr";
	}

	/**
	 * @desc 注册当前服务与配置中心服务端(也可以时zookeeper/redis)的心跳服务,获取服务端配置信息
	 * @param context 配置中心上线文信息对象
	 */
	@Override
	public void register(ConfigcenterContext context) {
		// 连接zookeeper服务端
		ZkConnection zkConnection = new ZkConnection(zkServers);
		zkClient = new ZkClient(zkConnection, 10000);

		// 判断zookeeper的指定目录下是否存在配置中心相关的信息,如果不存在则创建
		String appParentPath = ROOT_PATH + "/" + context.getEnv() + "/" + context.getApp() + "/nodes";
		if (!zkClient.exists(appParentPath)) {
			zkClient.createPersistent(appParentPath, true);
		}
		// 获取当前应用节点
		String appNodePath = appParentPath + "/" + context.getNodeId();
		// 创建node节点
		zkClient.createEphemeral(appNodePath);

		zkClient.subscribeDataChanges(appParentPath, new IZkDataListener() {
			@Override
			public void handleDataDeleted(String arg) {
			}

			@Override
			public void handleDataChange(String path, Object data) {
				if (data == null || StringUtils.isBlank(data.toString())) return;
				if (NOTIFY_UPLOAD_CMD.equals(data)) {
					logger.info("receive cmd[{}] from path[{}]", data, path);
					Properties properties = ResourceUtils.getAllProperties();
					context.syncConfigToServer(properties, false);
					logger.info("process cmd[{}] ok~", data);
				} else {
					try {
						Map<String, Object> changeDatas = JSON.parseObject(data.toString(), Map.class);
						context.updateConfig(changeDatas);
					} catch (Exception e) {
						logger.error("updateConfig error", e);
					}
				}
			}
		});
	}

	/**
	 * @desc 断开当前服务与配置中心服务端的链接
	 */
	@Override
	public void unRegister() {
		zkClient.close();
	}
}